package com.java.star.mall.front.service.impl;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson2.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.java.star.mall.common.constant.data.AddressConstant;
import com.java.star.mall.common.constant.data.ShowStatusConstant;
import com.java.star.mall.common.exception.BusinessException;
import com.java.star.mall.common.response.JsonPage;
import com.java.star.mall.common.response.StatusCode;
import com.java.star.mall.common.utils.Asserts;
import com.java.star.mall.front.dao.mapper.AddressMapper;
import com.java.star.mall.front.pojo.authentication.CurrentPrincipal;
import com.java.star.mall.front.pojo.entity.Address;
import com.java.star.mall.front.pojo.param.*;
import com.java.star.mall.front.pojo.vo.AddressVO;
import com.java.star.mall.front.pojo.vo.GeoCoderAddressVO;
import com.java.star.mall.front.properties.WxProperties;
import com.java.star.mall.front.service.AddressService;
import com.java.star.mall.front.util.CurrentPrincipalUtils;
import com.java.star.mall.front.util.DesensitizationUtils;
import com.java.star.mall.front.util.RestTemplateUtils;
import com.java.star.mall.front.util.WxSigUtils;
import io.jsonwebtoken.lang.Collections;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 用户地址Service实现类
 */
@Service
public class AddressServiceImpl implements AddressService {

    @Autowired
    private WxProperties wxProperties;

    @Autowired
    private AddressMapper addressMapper;

    /**
     * 获取腾讯地图用户的地址
     *
     * @param userLocationParam 用户经纬度参数
     * @return 腾讯地图逆地址解析的VO类
     * @link 参考此文档： https://lbs.qq.com/service/webService/webServiceGuide/webServiceGcoder
     */
    @Override
    public GeoCoderAddressVO getUserLocation(UserLocationParam userLocationParam) {
        //进行请求参数装填
        ReGeocoderRequestParam reGeocoderRequestParam = getGeocoderRequestParam(userLocationParam);

        //请求用户地址
        String result = RestTemplateUtils.get(wxProperties.getMap().getUrl(), reGeocoderRequestParam);

        //解析用户地址
        return analysisAddress(result);
    }

    /**
     * 获取腾讯地图用户的地址
     *
     * @param address 用户地市信息
     * @return 腾讯地图逆地址解析的VO类
     * @link 参考此文档： https://lbs.qq.com/service/webService/webServiceGuide/webServiceGeocoder
     */
    @Override
    public GeoCoderAddressVO getUserLocationByCityInfo(String address) {
        //1.根据用户地市信息，获取经纬度
        //1.1 进行请求参数装填
        GeocoderRequestParam geocoderRequestParam = getGeocoderRequestParam(address);

        //1.2 请求地址的经纬度信息
        String result = RestTemplateUtils.get(wxProperties.getMap().getUrl(), geocoderRequestParam);

        //1.3解析经纬度
        UserLocationParam userLocationParam = analysisLatitudeAndLongitude(result);

        //2.根据经纬度获取用户地址
        return this.getUserLocation(userLocationParam);
    }

    /**
     * 装填腾讯地图逆地址解析的请求参数
     *
     * @param userLocationParam 用户经纬度
     * @return 腾讯地图逆地址解析的请求参数实体
     */
    private ReGeocoderRequestParam getGeocoderRequestParam(UserLocationParam userLocationParam) {
        ReGeocoderRequestParam reGeocoderRequestParam = new ReGeocoderRequestParam();
        reGeocoderRequestParam.setKey(wxProperties.getMap().getKey());
        reGeocoderRequestParam.setLocation(userLocationParam.getLatitude() + "," + userLocationParam.getLongitude());
        String sig;
        try {
            sig = WxSigUtils.wxMapSig(wxProperties.getMap().getUrl(), wxProperties.getMap().getSecretKey(), reGeocoderRequestParam);
        } catch (URISyntaxException e) {
            throw new BusinessException(StatusCode.APP_ERROR, "签名异常");
        }
        reGeocoderRequestParam.setSig(sig);
        return reGeocoderRequestParam;
    }

    /**
     * 解析用户地址
     *
     * @param result 请求腾讯地图API所返回的JSON响应数据
     */
    private GeoCoderAddressVO analysisAddress(String result) {
        Asserts.isTrue(StringUtils.isEmpty(result), StatusCode.APP_ERROR, "未能查询到用户地址");

        JSONObject jsonObject = JSONObject.parseObject(result);
        Asserts.isTrue(!jsonObject.containsKey("status") || !jsonObject.getInteger("status").equals(0)
                , StatusCode.APP_ERROR, "用户地址数据请求失败");

        //获取数据
        JSONObject dataJson = jsonObject.getJSONObject("result");
        //获取省份
        String province = dataJson.getJSONObject("address_component").getString("province");
        //获取城市
        String city = dataJson.getJSONObject("address_component").getString("city");
        //获取地区
        String district = dataJson.getJSONObject("address_component").getString("district");
        //获取镇/街道
        String town = dataJson.getJSONObject("address_reference").getJSONObject("town").getString("title");
        //获取具体地标
        String landmark = dataJson.getJSONObject("address_reference").getJSONObject("landmark_l2").getString("title");

        //装填数据
        return new GeoCoderAddressVO(province, city, district, town, landmark);
    }

    /**
     * 解析经纬度地址
     *
     * @param result 请求腾讯地图API所返回的JSON响应数据
     * @return 用户所在位置参数类
     */
    private UserLocationParam analysisLatitudeAndLongitude(String result) {
        Asserts.isTrue(StringUtils.isEmpty(result), StatusCode.APP_ERROR, "未能查询到经纬度地址");

        JSONObject jsonObject = JSONObject.parseObject(result);
        Asserts.isTrue(!jsonObject.containsKey("status") || !jsonObject.getInteger("status").equals(0)
                , StatusCode.APP_ERROR, "用户经纬度数据请求失败");

        //获取数据
        JSONObject dataJson = jsonObject.getJSONObject("result");
        //获取纬度
        String latitude = dataJson.getJSONObject("location").getString("lat");
        //获取经度
        String longitude = dataJson.getJSONObject("location").getString("lng");

        //装填数据
        UserLocationParam userLocationParam = new UserLocationParam();
        userLocationParam.setLatitude(latitude);
        userLocationParam.setLongitude(longitude);
        return userLocationParam;
    }

    /**
     * 装填腾讯地图地址解析的请求参数
     *
     * @param address 地市信息，包含省市区地址
     * @return 腾讯地图逆地址解析的请求参数实体
     */
    private GeocoderRequestParam getGeocoderRequestParam(String address) {
        GeocoderRequestParam geocoderRequestParam = new GeocoderRequestParam();
        geocoderRequestParam.setKey(wxProperties.getMap().getKey());
        geocoderRequestParam.setAddress(address);
        String sig;
        try {
            sig = WxSigUtils.wxMapSig(wxProperties.getMap().getUrl(), wxProperties.getMap().getSecretKey(), geocoderRequestParam);
        } catch (URISyntaxException e) {
            throw new BusinessException(StatusCode.APP_ERROR, "签名异常");
        }
        geocoderRequestParam.setSig(sig);
        return geocoderRequestParam;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insert(AddressParam addressParam) {
        //获取当前登录的用户
        CurrentPrincipal currentPrincipal = CurrentPrincipalUtils.getCurrentPrincipal();

        //判断用户当前新增的地址是否设为了默认地址，如果设置了，需要将之前设置的地址更改为非默认
        hasOtherDefaultAddress(addressParam.getIsDefault(), currentPrincipal);

        //装填数据库插入参数
        Address address = new Address();
        BeanUtils.copyProperties(addressParam, address);
        address.setWxUserId(currentPrincipal.getId());
        address.setShowStatus(ShowStatusConstant.SHOW);
        Date now = new Date();
        address.setGmtCreate(now);
        address.setGmtUpdate(now);
        //插入数据
        addressMapper.insert(address);
    }

    @Override
    public JsonPage<AddressVO> list(Integer page, Integer pageSize) {
        //获取当前用户
        CurrentPrincipal currentPrincipal = CurrentPrincipalUtils.getCurrentPrincipal();

        //分页查询用户收货地址
        Page<Object> p = PageHelper.startPage(page, pageSize);
        List<Address> addressList = addressMapper.list(currentPrincipal.getId());

        //装填VO内容
        List<AddressVO> addressVOList = new ArrayList<>();
        if (!Collections.isEmpty(addressList)) {
            addressVOList = addressList.stream().map(address -> {
                AddressVO addressVO = new AddressVO();
                BeanUtils.copyProperties(address, addressVO);
                //手机号脱敏
                addressVO.setPhone(DesensitizationUtils.desensitizationPhone(address.getPhone()));
                return addressVO;
            }).collect(Collectors.toList());
        }

        //装填分页数据
        PageInfo<AddressVO> pageInfo = new PageInfo<>(addressVOList);
        pageInfo.setTotal(p.getTotal());
        pageInfo.setPages(p.getPages());
        pageInfo.setPageNum(p.getPageNum());
        pageInfo.setPageSize(p.getPageSize());
        return JsonPage.restPage(pageInfo);
    }

    @Override
    public void delete(Integer addressId) {
        //查询地址信息是否存在
        Address address = addressMapper.findById(addressId);
        Asserts.isTrue(Objects.isNull(address), StatusCode.APP_ERROR, "要删除的收货地址不存在");

        //这里做逻辑删除，将收货地址的显示状态改为0
        address.setShowStatus(ShowStatusConstant.HIDE);
        address.setGmtUpdate(new Date());
        addressMapper.update(address);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDefault(Integer addressId) {
        //查询地址信息是否存在
        Address address = addressMapper.findById(addressId);
        Asserts.isTrue(Objects.isNull(address), StatusCode.APP_ERROR, "要修改默认状态的收货地址不存在");

        //状态取反
        String isDefault = AddressConstant.DEFAULT_ADDRESS.equals(address.getIsDefault()) ?
                AddressConstant.UN_DEFAULT_ADDRESS : AddressConstant.DEFAULT_ADDRESS;

        //判断用户如果做的是设置默认地址操作，那么需要把之前有的默认地址设置为非默认
        CurrentPrincipal currentPrincipal = CurrentPrincipalUtils.getCurrentPrincipal();
        hasOtherDefaultAddress(isDefault, currentPrincipal);

        //修改状态
        address.setIsDefault(isDefault);
        address.setGmtUpdate(new Date());
        addressMapper.update(address);
    }

    /**
     * 判断用户是否有其他默认收货地址，如果有，就取消掉
     *
     * @param isDefault        是否是默认地址: 0 非默认 1默认
     * @param currentPrincipal 当前用户对象
     */
    private void hasOtherDefaultAddress(String isDefault, CurrentPrincipal currentPrincipal) {
        if (AddressConstant.DEFAULT_ADDRESS.equals(isDefault)) {
            List<Address> addressList = addressMapper.listAddressByDefault(currentPrincipal.getId(), AddressConstant.DEFAULT_ADDRESS);
            if (!Collections.isEmpty(addressList)) {
                Address defaultAddress = addressList.get(0);
                defaultAddress.setIsDefault(AddressConstant.UN_DEFAULT_ADDRESS);
                defaultAddress.setGmtUpdate(new Date());
                addressMapper.update(defaultAddress);
            }
        }
    }

    @Override
    public AddressVO getAddress(Integer addressId) {
        Address address = addressMapper.findById(addressId);
        AddressVO addressVO = new AddressVO();
        BeanUtils.copyProperties(address, addressVO);
        return addressVO;
    }

    @Override
    public void update(AddressParam addressParam) {
        //获取当前登录的用户
        CurrentPrincipal currentPrincipal = CurrentPrincipalUtils.getCurrentPrincipal();

        //判断用户当前修改的地址是否设为了默认地址，如果设置了，需要将之前设置的地址更改为非默认
        hasOtherDefaultAddress(addressParam.getIsDefault(), currentPrincipal);

        //装填数据库修改参数
        Address address = new Address();
        BeanUtils.copyProperties(addressParam, address);
        address.setGmtUpdate(new Date());

        //修改数据
        addressMapper.update(address);
    }

    @Override
    public AddressVO getDefaultAddress(Integer userId) {
        AddressVO addressVO = new AddressVO();
        //查询用户的默认地址，如果有，就直接返回
        List<Address> addressDefaultList = addressMapper.listAddressByDefault(userId, AddressConstant.DEFAULT_ADDRESS);
        if (!Collections.isEmpty(addressDefaultList)) {
            Address defaultAddress = addressDefaultList.get(0);
            BeanUtils.copyProperties(defaultAddress, addressVO);
            return addressVO;
        }

        //如果没有默认地址，查询用户的非默认地址列表，默认取第1个地址返回
        List<Address> addressList = addressMapper.listAddressByDefault(userId, AddressConstant.UN_DEFAULT_ADDRESS);
        if (!Collections.isEmpty(addressList)) {
            Address address = addressList.get(0);
            BeanUtils.copyProperties(address, addressVO);
            return addressVO;
        }

        return addressVO;
    }

}
